﻿//=============================================================================
//【 Stack 】
//-----------------------------------------------------------------------------
///**
//  @file       Stack.h
//  @brief      Stack
//  @author     Riki
//*/
//=============================================================================

#pragma once

//-------------------------------------------------------------------------
//
//-------------------------------------------------------------------------
namespace LNote
{
namespace Core
{
namespace Base
{

//=============================================================================
// ■ Stack クラス
//-----------------------------------------------------------------------------
///**
//  @brief      サイズ固定のスタッククラス
//
//  @par
//              STL を使って lib を作った時は VisualC++ のバージョンによって
//              リンクできないことがあるため、これを用意してあります。<br>
//              そのためこれは基本的に内部用です。
//              <br>
//              ただ、STL のものよりも数倍(作者の環境では7倍くらい)早いので
//              使い道はあるかもしれません。
//*/
//=============================================================================
template< typename TYPE_ > class Stack
    : public NonCopyable
{
public:

	//---------------------------------------------------------------------
	///**
	//  @brief      デフォルトコンストラクタ
	//
	//  @par
	//              デフォルトコンストラクタで作成した場合は
	//              そのあとに setCapacity() を呼んで領域を確保してください。
	//*/
	//---------------------------------------------------------------------
    Stack();

	//---------------------------------------------------------------------
	///**
	//  @brief      コンストラクタ
	//
	//  @param[in]  capacity_ : 格納できる要素数
	//*/
	//---------------------------------------------------------------------
	explicit Stack( int capacity_ );
    
	/// デストラクタ
	~Stack();

public:

	//---------------------------------------------------------------------
	///**
	//  @brief      領域の再確保
	//
	//  @param[in]  capacity_ : 格納できる要素数
	//*/
	//---------------------------------------------------------------------
	void setCapacity( int capacity_ );

	//---------------------------------------------------------------------
	///**
	//  @brief      空かどうかを判定する
	//*/
	//---------------------------------------------------------------------
	bool empty() const;

	//---------------------------------------------------------------------
	///**
	//  @brief      要素数の取得
	//*/
	//---------------------------------------------------------------------
	int size() const;

	//---------------------------------------------------------------------
	///**
	//  @brief      全ての要素を削除 ( デストラクタ呼び出し )
	//*/
	//---------------------------------------------------------------------
	void clear();

	//---------------------------------------------------------------------
	///**
	//  @brief      先頭に追加 ( コピーコンストラクタ呼び出し )
	//
	//  @retval     true  : 成功
	//  @retval     false : これ以上追加できない
	//*/
	//---------------------------------------------------------------------
	bool push( const TYPE_& value_ );

	//---------------------------------------------------------------------
	///**
	//  @brief      先頭を削除 ( デストラクタ呼び出し )
	//*/
	//---------------------------------------------------------------------
	void pop();

	//---------------------------------------------------------------------
	///**
	//  @brief      先頭の要素の取得
	//*/
	//---------------------------------------------------------------------
	TYPE_& top() const;

private:

    struct
    {
	    TYPE_*	mValues;	///< 配列本体
	    int		mSize;		///< 現在の要素数
	    int		mCapacity;	///< 要素の最大数
	    int		mBack;		///< 終端。これのひとつ前までが要素があるところ
    } _c;
};

//-------------------------------------------------------------------------

// デフォルトコンストラクタ
template< class TYPE_ > inline Stack< TYPE_ >::Stack()
{
    memset( &_c, 0, sizeof( _c ) );
}

// コンストラクタ
template< class TYPE_ > inline Stack< TYPE_ >::Stack( int capacity_ )
{
    memset( &_c, 0, sizeof( _c ) );

	if ( capacity_ <= 0 ) { return; }
	_c.mCapacity = capacity_;
	_c.mValues = static_cast< TYPE_* >( OPERATOR_NEW( sizeof( TYPE_ ) * _c.mCapacity ) );
}

// デストラクタ
template< class TYPE_ > inline Stack< TYPE_ >::~Stack()
{
	clear();
	LN_OPERATOR_DELETE( _c.mValues );
}

// 領域の再確保
template< class TYPE_ > inline void Stack< TYPE_ >::setCapacity( int capacity_ )
{
	clear();
	LN_OPERATOR_DELETE( _c.mValues );
	_c.mCapacity = 0;
	if ( capacity_ <= 0 ) { return; }
	_c.mCapacity = capacity_;
	_c.mValues = static_cast< TYPE_* >( LN_OPERATOR_NEW( sizeof( TYPE_ ) * _c.mCapacity ) );
}

// 空かどうかを判定する
template< class TYPE_ > inline bool Stack< TYPE_ >::empty() const
{
	return ( _c.mSize == 0 );
}

// 要素数の取得
template< class TYPE_ > inline int Stack< TYPE_ >::size() const
{
    return _c.mSize;
}

// 全ての要素を削除 ( デストラクタ呼び出し )
template< class TYPE_ > inline void Stack< TYPE_ >::clear()
{
	if ( _c.mValues )
	{
		for ( int i = 0; i < _c.mBack; ++i )
		{
			// デストラクタ呼び出し
			_c.mValues[ i ].~TYPE_();
		}
		_c.mBack = _c.mSize = 0;
	}
}

// 先頭に追加 ( コピーコンストラクタ呼び出し )
template< class TYPE_ > inline bool Stack< TYPE_ >::push( const TYPE_& value_ )
{
	if ( _c.mSize >= _c.mCapacity )
	{
		// 警告表示
		return false;
	}

	// mBack の位置に対してコピーコンストラクタ呼び出し
    ::new ( &_c.mValues[ _c.mBack ] ) TYPE_( value_ );
	++_c.mBack;
	++_c.mSize;

    return true;
}

// 先頭を削除 ( デストラクタ呼び出し )
template< class TYPE_ > inline void Stack< TYPE_ >::pop()
{
	if ( _c.mSize <= 0 )
	{
		return;
	}

	--_c.mBack;
	// デストラクタ呼び出し
	_c.mValues[ _c.mBack ].~TYPE_();
	--_c.mSize;
}

// 先頭の要素の取得
template< class TYPE_ > inline TYPE_& Stack< TYPE_ >::top() const
{
	return _c.mValues[ _c.mBack - 1 ];
}

//-------------------------------------------------------------------------
//
//-------------------------------------------------------------------------

} // namespace Base
} // namespace Core

} // namespace LNote

//=============================================================================
//
//=============================================================================